//
//  HMCharacteristic.swift
//  home
//
//  Created by Yun Zeng on 2018/11/25.
//  Copyright © 2018 Yun Zeng. All rights reserved.
//

import Foundation

// 属性 Characteristic 是 Service 描述的基本单元

// 属性支持的格式
enum HMCharacteristicFormat: String, Codable {
    case string
    case bool
    case float
    case uint8
    case uint16
    case uint32
    case int32
    case tlv8
}

// 属性描述的单位
enum HMCharacteristicUint: String, Codable {
    case percentage
    case celsius
    case lux
    case seconds
}

// 属性的类型
enum HMCharacteristicType: String, Codable {
    case unknown = "0"
    case name = "1"
    case model = "3"
    case manufacturer = "2"
    case serialNumber = "4"
    case firmwareRevision = "5"
    
    case currentTemperature = "11"
    case currentRelativeHumidity = "12"
    case currentAmbientLightLevel = "13"
    case currentAmbientInfraredLevel = "14"
    
    case contactSensorState = "15"
    case on = "16"
    case targetTemperature = "17"
    case airConditionerMode = "18"
    case airConditionerRotationMode = "19"
    case airConditionerWindSpeed = "1A"
    
    case screenBrightness = "1B"
    case currentTime = "1C"
    case volume = "1D"
    case musicName = "1E"
    
    case level = "21"
    case color = "22"
    case colorTemperature = "29"
    
    case coordinatorNetAddr = "23"
    case coordinatorMacAddr = "24"
    case coordinatorPanId = "25"
    case coordinatorExtPanId = "26"
    case coordinatorChannel = "27"
    case coordinatorPermitJoin = "28"
}

//
// 属性
// 服务描述的基本单元，用户操作查看的基本单元
// 例如: 开关的状态，空调的模式，门磁的状态，温湿度计的状态等
//
class HMCharacteristic: Codable {
    
    // 指向属性所属的服务
    var service: HMService?
    
    // 属性描述
    var id: Int
    
    // 属性类型, 例如: 温度值、湿度值、开关状态、门磁状态、空调温度等
    var type: HMCharacteristicType {
        get {
            guard let t = HMCharacteristicType(rawValue: self._type) else {
                return .unknown
            }
            return t
        }
        set {
            self._type = newValue.rawValue
        }
    }
    
    // 属性值得格式，例如: 字符串(string)，整形(int32)，布尔型(bool) 等
    var format: HMCharacteristicFormat {
        get {
            guard let f = HMCharacteristicFormat(rawValue: self._format) else {
                return .int32
            }
            return f
        }
        set {
            self._format = newValue.rawValue
        }
    }
    
    // 属性值的单位, 例如: 百分比(percentage)、摄氏度(celsius)、流明(lux) 等
    var unit: HMCharacteristicUint? {
        get {
            if let value = self._unit, let u = HMCharacteristicUint(rawValue: value) {
                return u
            }
            return nil
        }
        set {
            self._unit = newValue?.rawValue
        }
    }
    
    
    var value: AnyJSONType? {
        didSet {
            self.service?.needUpdate(state: .online)
        }
    }
    
    func setValue<T>(value: T, max: T? = nil, min :T? = nil, step: T? = nil) where T: JSONType {
        self.value = AnyJSONType(value)
        if let v = max {
            self.maxValue = AnyJSONType(v)
        }
        if let v = min {
            self.minValue = AnyJSONType(v)
        }
        if let v = step {
            self.stepValue = AnyJSONType(v)
        }
    }
    
    var maxValue: AnyJSONType?
    var minValue: AnyJSONType?
    var stepValue: AnyJSONType?

    private var _unit: String?
    private var _type: String = HMCharacteristicType.unknown.rawValue
    private var _format: String = HMCharacteristicFormat.int32.rawValue
    private enum CodingKeys: String, CodingKey {
        case id = "cid"
        case _type = "type"
        case _format = "format"
        case _unit = "unit"
        case value
        case maxValue = "max"
        case minValue = "min"
        case stepValue = "step"
    }
    
    init(id: Int = 0, type: HMCharacteristicType, format: HMCharacteristicFormat) {
        self.id = id
        self.type = type
        self.format = format
    }
}


// 打印调试信息
extension HMCharacteristic: CustomStringConvertible {
    var description: String {
        let data = try! JSONEncoder().encode(self)
        return String(data: data, encoding: .utf8)!
    }
}
